/*
 * Copyright 2002-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.event;

import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.core.ResolvableType;
import org.springframework.util.ErrorHandler;

/**
 * Simple implementation of the {@link ApplicationEventMulticaster} interface.
 *
 * <p>Multicasts all events to all registered listeners, leaving it up to
 * the listeners to ignore events that they are not interested in.
 * Listeners will usually perform corresponding {@code instanceof}
 * checks on the passed-in event object.
 *
 * <p>By default, all listeners are invoked in the calling thread.
 * This allows the danger of a rogue listener blocking the entire application,
 * but adds minimal overhead. Specify an alternative task executor to have
 * listeners executed in different threads, for example from a thread pool.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @author Brian Clozel
 * @see #setTaskExecutor
 */
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	private @Nullable Executor taskExecutor;

	private @Nullable ErrorHandler errorHandler;

	private volatile @Nullable Log lazyLogger;


	/**
	 * Create a new SimpleApplicationEventMulticaster.
	 */
	public SimpleApplicationEventMulticaster() {
	}

	/**
	 * Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
	 */
	public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
		setBeanFactory(beanFactory);
	}


	/**
	 * Set a custom executor (typically a {@link org.springframework.core.task.TaskExecutor})
	 * to invoke each listener with.
	 * <p>Default is equivalent to {@link org.springframework.core.task.SyncTaskExecutor},
	 * executing all listeners synchronously in the calling thread.
	 * <p>Consider specifying an asynchronous task executor here to not block the caller
	 * until all listeners have been executed. However, note that asynchronous execution
	 * will not participate in the caller's thread context (class loader, transaction context)
	 * unless the TaskExecutor explicitly supports this.
	 * <p>{@link ApplicationListener} instances which declare no support for asynchronous
	 * execution ({@link ApplicationListener#supportsAsyncExecution()} always run within
	 * the original thread which published the event, for example, the transaction-synchronized
	 * {@link org.springframework.transaction.event.TransactionalApplicationListener}.
	 * @since 2.0
	 * @see org.springframework.core.task.SyncTaskExecutor
	 * @see org.springframework.core.task.SimpleAsyncTaskExecutor
	 */
	public void setTaskExecutor(@Nullable Executor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}

	/**
	 * Return the current task executor for this multicaster.
	 * @since 2.0
	 */
	protected @Nullable Executor getTaskExecutor() {
		return this.taskExecutor;
	}

	/**
	 * Set the {@link ErrorHandler} to invoke in case an exception is thrown
	 * from a listener.
	 * <p>Default is none, with a listener exception stopping the current
	 * multicast and getting propagated to the publisher of the current event.
	 * If a {@linkplain #setTaskExecutor task executor} is specified, each
	 * individual listener exception will get propagated to the executor but
	 * won't necessarily stop execution of other listeners.
	 * <p>Consider setting an {@link ErrorHandler} implementation that catches
	 * and logs exceptions (a la
	 * {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_SUPPRESS_ERROR_HANDLER})
	 * or an implementation that logs exceptions while nevertheless propagating them
	 * (for example, {@link org.springframework.scheduling.support.TaskUtils#LOG_AND_PROPAGATE_ERROR_HANDLER}).
	 * @since 4.1
	 */
	public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
		this.errorHandler = errorHandler;
	}

	/**
	 * Return the current error handler for this multicaster.
	 * @since 4.1
	 */
	protected @Nullable ErrorHandler getErrorHandler() {
		return this.errorHandler;
	}

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, null);
	}

	/**
	 * 广播事件给所有注册的监听器
	 *
	 * @param event 应用程序事件，不能为空
	 * @param eventType 事件的类型，可以为空如果提供，则用于优化事件分发
	 *
	 * 此方法负责将给定的应用程序事件广播给所有感兴趣的监听器监听器是通过反射机制动态确定的，
	 * 并且根据事件类型进行过滤如果配置了异步执行器并且监听器支持异步执行，则在异步任务执行器中执行监听器，
	 * 否则直接同步执行此方法确保即使在执行异步任务时遇到拒绝执行异常（例如，在关闭过程中），
	 * 也能本地调用监听器，确保事件的传递
	 */
	@Override
	public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
	    // 确定事件类型，如果未提供，则基于事件实例确定
	    ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
	    // 获取任务执行器，用于异步事件处理
	    Executor executor = getTaskExecutor();
	    // 遍历所有与事件和事件类型匹配的监听器
	    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
	        // 如果配置了执行器且监听器支持异步执行，则在异步任务执行器中执行监听器
	        if (executor != null && listener.supportsAsyncExecution()) {
	            try {
	                // 提交异步任务给执行器
	                executor.execute(() -> invokeListener(listener, event));
	            }
	            catch (RejectedExecutionException ex) {
	                // 可能是在关闭过程中 -> 在本地调用监听器而不是抛出异常
	                invokeListener(listener, event);
	            }
	        }
	        else {
	            // 直接同步调用监听器
	            invokeListener(listener, event);
	        }
	    }
	}

	/**
	 * Invoke the given listener with the given event.
	 * @param listener the ApplicationListener to invoke
	 * @param event the current event to propagate
	 * @since 4.1
	 */
	/**
	 * 调用应用监听器处理事件
	 *
	 * 此方法负责在捕获到错误时调用指定的应用监听器，并且根据错误处理器来处理可能发生的错误
	 * 它是应用事件机制的核心部分，确保事件被适当处理，并且错误不会导致系统崩溃
	 *
	 * @param listener 要调用的事件监听器，它会对接收到的事件进行处理
	 * @param event 要处理的应用事件，该事件包含特定的事件数据
	 */
	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
	    // 获取错误处理器，用于处理在事件监听器执行过程中可能发生的错误
	    ErrorHandler errorHandler = getErrorHandler();

	    if (errorHandler != null) {
	        // 如果存在错误处理器，尝试调用监听器并捕获可能发生的错误
	        try {
	            doInvokeListener(listener, event);
	        }
	        catch (Throwable err) {
	            // 错误捕获时，调用错误处理器来处理错误
	            errorHandler.handleError(err);
	        }
	    }
	    else {
	        // 如果没有错误处理器，直接调用监听器，不进行错误捕获
	        doInvokeListener(listener, event);
	    }
	}

	@SuppressWarnings({"rawtypes", "unchecked"})
	/**
	 * 调用应用事件监听器
	 *
	 * @param listener 应用事件监听器实例
	 * @param event 应用事件实例
	 */
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
	    try {
	        // 调用监听器的事件处理方法
	        listener.onApplicationEvent(event);
	    }
	    catch (ClassCastException ex) {
	        // 捕获类型转换异常
	        String msg = ex.getMessage();
	        if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
	                (event instanceof PayloadApplicationEvent payloadEvent &&
	                        matchesClassCastMessage(msg, payloadEvent.getPayload().getClass()))) {
	            // 可能是lambda表达式定义的监听器，我们无法解析其泛型事件类型
	            // -> 让我们抑制这个异常
	            Log loggerToUse = this.lazyLogger;
	            if (loggerToUse == null) {
	                // 如果lazyLogger为空，则初始化它
	                loggerToUse = LogFactory.getLog(getClass());
	                this.lazyLogger = loggerToUse;
	            }
	            // 如果启用了TRACE日志级别，则记录非匹配事件类型的调试信息
	            if (loggerToUse.isTraceEnabled()) {
	                loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
	            }
	        }
	        else {
	            // 如果异常消息不匹配类型转换问题，则重新抛出异常
	            throw ex;
	        }
	    }
	}

	private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
		// On Java 8, the message starts with the class name: "java.lang.String cannot be cast..."
		if (classCastMessage.startsWith(eventClass.getName())) {
			return true;
		}
		// On Java 11, the message starts with "class ..." a.k.a. Class.toString()
		if (classCastMessage.startsWith(eventClass.toString())) {
			return true;
		}
		// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
		int moduleSeparatorIndex = classCastMessage.indexOf('/');
		if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
			return true;
		}
		// Assuming an unrelated class cast failure...
		return false;
	}

}
